
-- this method of encoding decimal numbers in the type system is a 
-- refined method based on a fixed-length encoding of binary numbers 
-- developed by Chris Okasaki

-- Arbitrary precision decimal types

module Static ( D0(D0), D1(D1), D2(D2), D3(D3), D4(D4),
                D5(D5), D6(D6), D7(D7), D8(D8), D9(D9),
                DNil(DNil), Cardinal(..), )  where
import Data.Array.IArray

-- The digits:
data D0 a = D0 a
    deriving Show
data D1 a = D1 a
    deriving Show
data D2 a = D2 a
    deriving Show
data D3 a = D3 a
    deriving Show
data D4 a = D4 a
    deriving Show
data D5 a = D5 a
    deriving Show
data D6 a = D6 a
    deriving Show
data D7 a = D7 a
    deriving Show
data D8 a = D8 a
    deriving Show
data D9 a = D9 a
    deriving Show

-- To decide if it makes sense to implement a prettier method
-- printing the type-level numerals makes sense
-- (an explicit serialization mechanism would be needed then)

-- A method which transforms a type-level list of digits
-- into a number. This is similar to the way cardToInt
-- for Peano numerals works.
-- The second argument is an accumulator.

class Digits ds where
    digitsToNum:: (Num a) => ds -> a -> a

data DNil = DNil -- zero size
    deriving Show

instance Digits DNil where
    digitsToNum _ acc = acc
instance (Digits ds) => Digits (D0 ds) where
    digitsToNum d acc = digitsToNum (unwrap d) (10*acc + 0)
instance (Digits ds) => Digits (D1 ds) where
    digitsToNum d acc = digitsToNum (unwrap d) (10*acc + 1)
instance (Digits ds) => Digits (D2 ds) where
    digitsToNum d acc = digitsToNum (unwrap d) (10*acc + 2)
instance (Digits ds) => Digits (D3 ds) where
    digitsToNum d acc = digitsToNum (unwrap d) (10*acc + 3)    
instance (Digits ds) => Digits (D4 ds) where
    digitsToNum d acc = digitsToNum (unwrap d) (10*acc + 4)
instance (Digits ds) => Digits (D5 ds) where
    digitsToNum d acc = digitsToNum (unwrap d) (10*acc + 5)
instance (Digits ds) => Digits (D6 ds) where
    digitsToNum d acc = digitsToNum (unwrap d) (10*acc + 6)
instance (Digits ds) => Digits (D7 ds) where
    digitsToNum d acc = digitsToNum (unwrap d) (10*acc + 7)
instance (Digits ds) => Digits (D8 ds) where
    digitsToNum d acc = digitsToNum (unwrap d) (10*acc + 8)
instance (Digits ds) => Digits (D9 ds) where
    digitsToNum d acc = digitsToNum (unwrap d) (10*acc + 9)

unwrap::d a -> a
unwrap = undefined

class (Digits ds) => Cardinal ds where
    cardToInt::ds -> Int
    cardToInt d = digitsToNum d 0

instance Cardinal DNil
instance (Digits ds) => Cardinal (D1 ds)
instance (Digits ds) => Cardinal (D2 ds)
instance (Digits ds) => Cardinal (D3 ds)
instance (Digits ds) => Cardinal (D4 ds)
instance (Digits ds) => Cardinal (D5 ds)
instance (Digits ds) => Cardinal (D6 ds)
instance (Digits ds) => Cardinal (D7 ds)
instance (Digits ds) => Cardinal (D8 ds)
instance (Digits ds) => Cardinal (D9 ds)

